package com.significantfiles.snapshot.engine;

import java.io.File;
import java.io.IOException;
import java.util.Collection;

import com.significantfiles.snapshot.config.TransactionStorageConfig;
import com.significantfiles.snapshot.engine.compiler.model.x.EntityInterfaceIsBrokenException;
import com.significantfiles.snapshot.engine.io.Snapshot;
import com.significantfiles.snapshot.engine.io.TransactionStorage;
import com.significantfiles.snapshot.engine.rt.CouldntCreateEntitySpaceException;
import com.significantfiles.snapshot.engine.rt.EntityFactory;
import com.significantfiles.snapshot.engine.rt.Model;
import com.significantfiles.snapshot.engine.structure.id.EntityIdFactory;
import com.significantfiles.snapshot.engine.tx.Transaction;
import com.significantfiles.snapshot.engine.tx.TransactionException;

public class EngineCore implements IEngine {

	// Index-Analyzer
	// Index-Listener
	// Transaction

	private TransactionStorage txStorage;

	private final EntityFactory modelProxyManager;

	private final Model model;
	
	public EngineCore( final EntityIdFactory idFactory, final TransactionStorageConfig txStorageConfig ) {
		if( idFactory == null )
			throw new NullPointerException();
		
		this.modelProxyManager = new EntityFactory( idFactory );
		this.model = new Model( );
		this.txStorage = new TransactionStorage( txStorageConfig );
	}

	@Override
	public void execute(final Transaction<?> tx)
			throws TransactionException {
		if (tx == null)
			throw new NullPointerException("Parameter:tx");

		if( this.txStorage.shouldCreateSnapshot() ) {
			createSnapshot();
		}

		txStorage.storeTx(tx);
		
		tx.execute(model);

		notifyIndexListeners(tx);
	}


	private void createSnapshot() throws TransactionException {
		try {
			this.model.writeSnapshot();
		} catch (final IOException e) {
			throw new TransactionException( "Couldn't create snapshot.", e);
		}
	}

	private void notifyIndexListeners(final Transaction<?> tx) {
		System.out.println( ">>> notify listeners" );
	}

	

	public void registerModelInterface(final Class<?> modelInterface) throws EntityInterfaceIsBrokenException, CouldntCreateEntitySpaceException {
		checkModelInterface(modelInterface);
		createProxyClass(modelInterface);
		
		model.createSpace( modelInterface );
	}
	
	private void createProxyClass(final Class<?> modelInterface) throws EntityInterfaceIsBrokenException {
		this.modelProxyManager.registerModelInterface(modelInterface);
	}

	public final <M> M createInstance(final Class<M> modelInterface) throws EntityInterfaceIsBrokenException {
		return this.modelProxyManager.createInstance(modelInterface);
	}

	private void checkModelInterface(Class<?> modelInterface) {
		// darf nur ein interface sein.
		// und nur interfaces oder simple types erlauben (String, Date, ...)

		// constraints werden analysiert.
	}

	public void registerDao(final Class<?> daoClass) {
		throw new UnsupportedOperationException();
	}

	public TransactionStorage getStorage() {
		return txStorage;
	}
	
}
